home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 February / EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso / earcd / comm2 / xprz351s.lha / Receive.c < prev    next >
C/C++ Source or Header  |  1995-01-03  |  25KB  |  803 lines

  1. /**********************************************************************
  2.  * Receive.c:  File reception routines for xprzmodem.library;
  3.  * Version 2.10, 12 February 1991, by Rick Huebner.
  4.  * Based closely on Chuck Forsberg's rz.c example ZModem code,
  5.  * but too pervasively modified to even think of detailing the changes.
  6.  * Released to the Public Domain; do as you like with this code.
  7.  *
  8.  * Version 2.50, 15 November 1991, CRC-32 additions by William M. Perkins.
  9.  * Version 2.63, 30 July 1993 build in locale, by Rainer Hess
  10.  * Version 3.1,  17 August 1993, added Auto-Blocksize by Rainer Hess
  11.  * Version 3.2,  10 Nov 1994, restored FTN Support by Robert Williamson
  12.  *
  13.  **********************************************************************/
  14.  
  15. #include "xprzmodem_all.h"
  16.  
  17. #define CATCOMP_NUMBERS
  18. #include "xprzmodem_catalog.h"
  19.  
  20. #ifdef DEBUGLOG
  21. extern void *DebugLog;
  22. #endif
  23.  
  24. /**********************************************************
  25.  *      long XProtocolReceive(struct XPR_IO *xio)
  26.  *
  27.  * Main file reception routine; called by comm program
  28.  **********************************************************/
  29. long __saveds __asm
  30. XProtocolReceive (register __a0 struct XPR_IO *xio)
  31. {
  32.   struct SetupVars *sv;
  33.   struct Vars *v;
  34.   UBYTE err = FALSE;
  35.  
  36.   /* Perform common setup and initializations */
  37.   if (!(v = setup (xio)))
  38.     return XPRS_FAILURE;
  39.  
  40.   v->Tryzhdrtype = ZRINIT;
  41.   v->Rxtimeout = v->FTNmode ? 600 : 100;
  42.  
  43. #ifdef KDEBUG
  44. KPrintF("\nXProtocolReceive\n");
  45. KPrintF("XprBaud:%ld  UserBaud:%ld\n",v->Baud,v->NewBaud);
  46. KPrintF("FtnMode:%s   DirectZap:%s   Nofiles:%s   SmallBlocks:%s\n",
  47.   (v->FTNmode ? "TRUE" : "FALSE"),
  48.   (v->dzap ? "TRUE" : "FALSE"),
  49.   (v->NoFiles ? "TRUE" : "FALSE"),
  50.   (v->SmallBlocks ? "TRUE" : "FALSE"));
  51. KPrintF("Rxtimeout:%ld\n",v->Rxtimeout);
  52. #endif
  53.  
  54.   sv = (void *) v->io.xpr_data;
  55.   if (sv->bufpos)
  56.     {
  57.       v->Modemchar = v->Modembuf;
  58.       if (sv->buflen > sizeof (v->Modembuf))
  59.         sv->buflen = sizeof (v->Modembuf);
  60.       memcpy (v->Modembuf, sv->bufpos, sv->buflen);
  61.       v->Modemcount = sv->buflen;
  62.     }
  63.  
  64.   /* first clear the inbound buffer */
  65.   if (v->FTNmode && v->io.xpr_sflush)   
  66.   {       
  67. #ifdef KDEBUG 
  68. KPrintF("Flushing\n");  
  69. #endif  
  70.     (*v->io.xpr_sflush) ();     
  71.   }   
  72.  
  73.   /* Transfer the files */
  74.   if (rcvbatch (v) == ERROR)
  75.   {
  76.     upderr (v, GetLocalString( &li, MSG_DOWNLOAD_USER_ERROR ), XPRU_DNLOAD);
  77.     err = TRUE;
  78.   }
  79.   else
  80.   {
  81.     updmsg (v, GetLocalString( &li, MSG_RECV_DONE ), XPRU_DNLOAD);
  82.   }
  83.   /* Clean up and return */
  84.   if (v->io.xpr_setserial && v->Oldstatus != -1)
  85.     (*v->io.xpr_setserial) (v->Oldstatus);
  86.   FreeMem (v->Filebuf, v->Filebufmax);
  87.   FreeMem (v, (long) sizeof (struct Vars));
  88.  
  89. #ifdef DEBUGLOG
  90.   if (DebugLog)
  91.   {
  92.     (*v->io.xpr_fclose) ((long) DebugLog);
  93.     DebugLog = NULL;
  94.   }
  95. #endif
  96.  
  97. #ifdef KDEBUG
  98. KPrintF("XProtcolReceive returning:%s\n",err ? "XPRS_FAILURE" : "XPRS_SUCCESS");
  99. #endif
  100.   return (err) ? XPRS_FAILURE : XPRS_SUCCESS;
  101. } /* End of long XProtocolReceive() */
  102.  
  103. /**********************************************************
  104.  *      short rcvbatch(struct Vars *v)
  105.  *
  106.  * Start the batch transfer
  107.  **********************************************************/
  108. short
  109. rcvbatch (struct Vars *v)
  110. {
  111. #ifdef DEBUGLOG
  112.   D (DEBUGINFO);
  113. #endif
  114. ignore_zcan:
  115.   switch (tryz (v))
  116.   {
  117.     case ZCOMPL:
  118.       return OK;
  119.     case ZFILE:
  120.       if (rzfiles (v) == OK)
  121.         return OK;
  122. /**/    case ZFIN:
  123.       if (v->NoFiles)
  124.         return OK;
  125.     case ZCAN:
  126.       if (v->FTNmode)
  127.         goto ignore_zcan;
  128.     }
  129.  
  130. #ifdef DEBUGLOG
  131.   D (DEBUGINFO);
  132. #endif
  133. #ifdef KDEBUG
  134. KPrintF("rcvbatch canit ERROR\n");
  135. #endif
  136.   canit (v);
  137.  
  138.   return ERROR;
  139. }                                /* End of short rcvbatch() */
  140.  
  141. /**********************************************************
  142.  *      short tryz(struct Vars *v)
  143.  *
  144.  * Negotiate with sender to start a file transfer
  145.  **********************************************************/
  146. short
  147. tryz (struct Vars *v)
  148. {
  149.   short n, errors = 0;
  150. /*  short flushs = 0; */
  151.  
  152. #ifdef DEBUGLOG
  153.   D (DEBUGINFO);
  154. #endif
  155.  
  156.   for (n = v->ErrorLimit; --n >= 0;)
  157.   {
  158.       /* Set max frame length and capability flags */
  159.       stohdr (v, (long) v->Tframlen);
  160.       v->Txhdr[ZF0] = CANFC32 | CANFDX | CANOVIO;
  161.       zshhdr (v, v->Tryzhdrtype);
  162.       sendbuf (v);
  163.  
  164.     again:
  165.       /* Check for abort from comm program */
  166.       if (v->io.xpr_chkabort && (*v->io.xpr_chkabort) ())
  167.       {
  168. #ifdef KDEBUG
  169. KPrintF("Host aborted us!!!\n");
  170. #endif
  171.         return ERROR;
  172.       }
  173.       switch (zgethdr (v))
  174.       {
  175. /*
  176.         case ZRQINIT:
  177.         case ZRINIT:
  178.           goto again;
  179. */
  180.         case ZFIN:                /* Sender has ended batch */
  181.           ackbibi (v);
  182.           return ZCOMPL;
  183.         case ZFILE:                   /* File name and info packet */
  184.           v->Zconv = v->Rxhdr[ZF0];   /* Suggested txt mode; ZCNL = text, */
  185.                                       /* ZCBIN = binary, 0 = don't know. */
  186.           v->Zmanag = v->Rxhdr[ZF1];  /* Suggested file management mode. */
  187.           v->Ztrans = v->Rxhdr[ZF2];  /* Suggested file transport mode. */
  188.           v->Tryzhdrtype = ZRINIT;
  189. /*          if (zrdata (v, v->Pktbuf, KSIZE) == GOTCRCW)    */
  190.           if (zrdata (v, v->Pktbuf, v->Ksize) == GOTCRCW) 
  191.             return ZFILE;
  192.           zshhdr (v, ZNAK);         /* Packet mangled, ask for retry */
  193.           sendbuf (v);
  194.           goto again;
  195.         case ZSINIT:                /* Special attention-grabbing string to use to */
  196.                                     /* interrupt sender */
  197.           if (zrdata (v, v->Attn, ZATTNLEN) == GOTCRCW)
  198.             zshhdr (v, ZACK);
  199.           else
  200.             zshhdr (v, ZNAK);
  201.           sendbuf (v);
  202.           goto again;
  203.         case ZFREECNT:                /* Sender wants to know how much room we've got */
  204.           stohdr (v, getfree ());
  205.           zshhdr (v, ZACK);
  206.           sendbuf (v);
  207.           goto again;
  208.         case ZCOMMAND:                /* Sender wants us to do remote commands, */
  209.                                       /* but we don't do requests. */
  210. /*          if (zrdata (v, v->Pktbuf, KSIZE) == GOTCRCW)    */
  211.           if (zrdata (v, v->Pktbuf, v->Ksize) == GOTCRCW) 
  212.           {
  213.             xprsprintf (v->Msgbuf, "%s: %s", GetLocalString( &li, MSG_IGNORING_COMMAND), v->Pktbuf);
  214.             upderr (v, v->Msgbuf, XPRU_DNLOAD);    /* Ignore and report all uploaded commands */
  215.             stohdr (v, 0L);           /* whilst telling sender they worked; */
  216.             do
  217.             {
  218.               zshhdr (v, ZCOMPL);    /* paranoia can be good for you... */
  219.               sendbuf (v);
  220.             }
  221.             while (++errors < v->ErrorLimit && zgethdr (v) != ZFIN);
  222.               ackbibi (v);
  223.             return ZCOMPL;
  224.           }
  225.           else
  226.             zshhdr (v, ZNAK);
  227.           sendbuf (v);
  228.           goto again;
  229.         case ZCOMPL:
  230.           goto again;
  231.         case ZCAN:
  232. #ifdef KDEBUG
  233. KPrintF("tryz: Got a ZCAN\n");
  234. #endif
  235.         case RCDO:
  236.           upderr (v, v->Msgbuf, XPRU_DNLOAD);
  237.           return ERROR;
  238.       }
  239.   }
  240. #ifdef KDEBUG
  241. KPrintF("tryz returning ERROR ,error limit:  %ld exceeded\n",v->ErrorLimit);
  242. #endif
  243.   return ERROR;
  244. }                                /* End of short tryz() */
  245.  
  246. /**********************************************************
  247.  *      short rzfiles(struct Vars *v)
  248.  *
  249.  * Receive a batch of files
  250.  **********************************************************/
  251. short
  252. rzfiles (struct Vars *v)
  253. {
  254.   struct SetupVars *sv;
  255.   short c;
  256.  
  257. #ifdef DEBUGLOG
  258.   D (DEBUGINFO);
  259. #endif
  260.  
  261.   /* Keep receiving files until end of batch or error */
  262.   while (TRUE)
  263.     {
  264.       if (v->FTNmode)
  265.         v->Filename[0]='\0';
  266.  
  267.       switch (c = rzfile (v))
  268.         {
  269. /**/        case ZFIN:
  270.             return OK;
  271.  
  272.         case ZEOF:
  273.         case ZSKIP:
  274.           if (v->FTNmode && strlen(v->Filename))
  275.           {
  276. #ifdef KDEBUG
  277. KPrintF("Returning XPRS_SUCCESS for ZEOF/ZSKIP in FTNmode\n");
  278. #endif
  279.             updstatus(v,v->Filename,XPRS_SUCCESS, XPRU_DNLOAD);
  280.           }
  281.           switch (tryz (v))
  282.             {
  283.             case ZCOMPL:
  284.               return OK;
  285.             case ZFILE:
  286.               break;
  287.             default:
  288.               return ERROR;
  289.             }
  290.           break;
  291.         default:
  292.           bfclose (v);
  293.           if (v->FTNmode && strlen(v->Filename))
  294.           {
  295. #ifdef KDEBUG
  296. KPrintF("Returning XPRS_FAILURE in FTNmode\n");
  297. #endif
  298.             updstatus (v,v->Filename,XPRS_FAILURE, XPRU_DNLOAD);  /* Tell the system it failed! */
  299.           }
  300.  
  301.           sv = (void *) v->io.xpr_data;
  302.           if (*sv->option_k == 'N' && v->io.xpr_extension >= 2
  303.               && v->io.xpr_unlink)
  304.             {
  305.               updmsg (v, GetLocalString( &li, MSG_DELETING_RECEIVED_FILE ), XPRU_DNLOAD);
  306.               (*v->io.xpr_unlink) (v->Filename);
  307.             }
  308.           else
  309.             updmsg (v, GetLocalString( &li, MSG_KEEPING_RECEIVED_FILE), XPRU_DNLOAD);
  310.           return c;
  311.         }
  312.     }
  313. }                                /* End of short rzfiles() */
  314.  
  315. /**********************************************************
  316.  *      short rzfile(struct Vars *v)
  317.  *
  318.  * Receive one file; file name packet already read into
  319.  * Pktbuf by tryz()
  320.  **********************************************************/
  321. short
  322. rzfile (struct Vars *v)
  323. {
  324.   short c, n;
  325.  
  326. #ifdef DEBUGLOG
  327.   D (DEBUGINFO);
  328. #endif
  329.  
  330.   /*
  331.      * Process file name packet; either open file and prepare to receive,
  332.      * or tell us to skip this one.
  333.    */
  334.   if (procheader (v) == ERROR)
  335.     return v->Tryzhdrtype = ZSKIP;
  336.  
  337.   n = v->ErrorLimit;
  338.   v->Rxbytes = v->Strtpos;
  339.   v->Eofseen = FALSE;
  340.  
  341.   /* Receive ZDATA frames until finished */
  342.   while (TRUE)
  343.     {
  344.       stohdr (v, v->Rxbytes);        /* Tell sender where to start frame */
  345.       zshhdr (v, ZRPOS);
  346.       sendbuf (v);
  347.     nxthdr:
  348.       /* Check for abort from comm program */
  349.       if (v->io.xpr_chkabort && (*v->io.xpr_chkabort) ())
  350.       {
  351. #ifdef KDEBUG
  352. KPrintF("Host aborted us!!!\n");
  353. #endif
  354.         return ERROR;
  355.       }
  356.       switch (c = zgethdr (v))        /* Wait for frame header */
  357.         {
  358.         default:
  359. #ifdef DEBUGLOG
  360.           xprsprintf (v->Msgbuf, "rzfile: zgethdr returned %ld\n", (long) c);
  361.           dlog (v, v->Msgbuf);
  362.           D (DEBUGINFO);
  363.  
  364. #endif
  365.           return ERROR;
  366.         case ZNAK:
  367.         case TIMEOUT:
  368.           if (--n < 0)
  369.             return ERROR;
  370. #ifdef DEBUGLOG
  371.           dlog (v, "rzfile: zgethdr NAK/Timeout\n");
  372.           D (DEBUGINFO);
  373. #endif
  374.           if (v->NoMask) v->xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_TIMEOUTS;
  375.           else v->xpru.xpru_updatemask = XPRU_DNLOAD | XPRU_ERRORMSG | XPRU_TIMEOUTS;
  376.           xprsprintf (strchr (v->Msgbuf, '\0'), "@ %ld; %ld %s",
  377.                       v->Rxbytes, (long) n, GetLocalString( &li, MSG_RETRIES_LEFT ));
  378.           v->xpru.xpru_errormsg = (char *) v->Msgbuf;
  379.           ++v->xpru.xpru_timeouts;
  380.           (*v->io.xpr_update) (&v->xpru);
  381.           continue;
  382.         case ZFILE:                /* Sender didn't see our ZRPOS yet; try again */
  383. /*          zrdata (v, v->Pktbuf, KSIZE);   */
  384.           zrdata (v, v->Pktbuf, v->Ksize);  
  385.                 /* Read and discard redundant */
  386.           continue;                /* filename packet */
  387.         case ZEOF:                /* End of file data */
  388.           if (v->Rxpos != v->Rxbytes)        /* We aren't in sync; go back */
  389.             {
  390.               xprsprintf (v->Msgbuf, GetLocalString( &li, MSG_BAD_EOF ),
  391.                           v->Rxbytes, v->Rxpos);
  392.               upderr (v, v->Msgbuf, XPRU_DNLOAD);
  393.               continue;
  394.             }
  395.           bfclose (v);                /* All done; close file */
  396. #ifdef DEBUGLOG
  397.           dlog (v, "rzfile: EOF\n");
  398.           D (DEBUGINFO);
  399. #endif
  400.           updmsg (v, GetLocalString( &li, MSG_EOF_RECEIVED ), XPRU_DNLOAD);
  401.           return c;
  402.         case ERROR:                /* Too much garbage while waiting for frame header */
  403.           if (--n < 0)
  404.             return ERROR;
  405. #ifdef DEBUGLOG
  406.           dlog (v, "rzfile: zgethdr garbage overflow\n");
  407.           D (DEBUGINFO);
  408. #endif
  409.           if (v->NoMask) v->xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_ERRORS;
  410.           else v->xpru.xpru_updatemask = XPRU_DNLOAD | XPRU_ERRORMSG | XPRU_ERRORS;
  411.           xprsprintf (strchr (v->Msgbuf, '\0'), "@ %ld; %ld %s",
  412.                       v->Rxbytes, (long) n, GetLocalString( &li, MSG_RETRIES_LEFT ));
  413.           v->xpru.xpru_errormsg = (char *) v->Msgbuf;
  414.           ++v->xpru.xpru_errors;
  415.           (*v->io.xpr_update) (&v->xpru);
  416.           zmputs (v, v->Attn);
  417.           continue;
  418.         case ZDATA:                /* More file data packets forthcoming */
  419.             if ((v->Rxpos > v->Rxbytes) || ((v->Rxpos + 2*(v->Rxcount)) < v->Rxbytes))
  420. /*          if (v->Rxpos != v->Rxbytes)     */
  421.             {    /* We aren't in sync; go back */
  422.               if (--n < 0)
  423.                 return ERROR;
  424.               if (v->NoMask) v->xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_ERRORS;
  425.               else v->xpru.xpru_updatemask = XPRU_DNLOAD | XPRU_ERRORMSG | XPRU_ERRORS;
  426.               xprsprintf (v->Msgbuf, GetLocalString( &li, MSG_DATA_AT_BAD_POSITION ),
  427.                           v->Rxbytes, v->Rxpos);
  428.               v->xpru.xpru_errormsg = (char *) v->Msgbuf;
  429.               ++v->xpru.xpru_errors;
  430.               (*v->io.xpr_update) (&v->xpru);
  431.               zmputs (v, v->Attn);
  432.               continue;
  433.             }
  434.           /* Receive file data packet(s) */
  435.         moredata:
  436.           /* Give comm program its timeslice if it needs one */
  437.           if (v->io.xpr_chkmisc)
  438.             (*v->io.xpr_chkmisc) ();
  439.           /* Check for abort from comm program */
  440.           if (v->io.xpr_chkabort && (*v->io.xpr_chkabort) ())
  441.           {
  442. #ifdef KDEBUG
  443. KPrintF("Host aborted us!!!\n");
  444. #endif
  445.             goto aborted;
  446.           }
  447. /*          switch (c = zrdata (v, v->Pktbuf, KSIZE))   */
  448.           switch (c = zrdata (v, v->Pktbuf, v->Ksize))  
  449.             {
  450.             case ZCAN:
  451. #ifdef KDEBUG
  452. KPrintF("rzfile: zdata Got a ZCAN\n");
  453. #endif
  454.             case RCDO:
  455.             aborted:
  456. #ifdef DEBUGLOG
  457.               dlog (v, "rzfile: zrdata returned CAN\n");
  458.               D (DEBUGINFO);
  459. #endif
  460.               upderr (v, GetLocalString( &li, MSG_TRANSFER_CANCELLED ), XPRU_DNLOAD);
  461.               return ERROR;
  462.             case ERROR:        /* CRC error or packet too long */
  463.               if (--n < 0)
  464.                 return ERROR;
  465. #ifdef DEBUGLOG
  466.               dlog (v, "rzfile: zrdata returned error\n");
  467.               D (DEBUGINFO);
  468. #endif
  469.               if (v->NoMask) v->xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_ERRORS;
  470.               else v->xpru.xpru_updatemask = XPRU_DNLOAD | XPRU_ERRORMSG | XPRU_ERRORS;
  471.               xprsprintf (strchr (v->Msgbuf, '\0'), "@ %ld; %ld %s",
  472.                           v->Rxbytes, (long) n, GetLocalString( &li, MSG_RETRIES_LEFT ));
  473.               v->xpru.xpru_errormsg = (char *) v->Msgbuf;
  474.               ++v->xpru.xpru_errors;
  475.               (*v->io.xpr_update) (&v->xpru);
  476. #ifdef DEBUGLOG
  477.               dlog (v, v->Msgbuf);
  478.               dlog (v, "\n");
  479.               D (DEBUGINFO);
  480. #endif
  481.               zmputs (v, v->Attn);
  482.               continue;
  483.             case TIMEOUT:
  484.               if (--n < 0)
  485.                 return ERROR;
  486. #ifdef DEBUGLOG
  487.               dlog (v, "rzfile: zrdata returned timeout\n");
  488.               D (DEBUGINFO);
  489. #endif
  490.               if (v->NoMask) v->xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_TIMEOUTS;
  491.               else v->xpru.xpru_updatemask = XPRU_DNLOAD | XPRU_ERRORMSG | XPRU_TIMEOUTS;
  492.               xprsprintf (strchr (v->Msgbuf, '\0'), "@ %ld; %ld %s",
  493.                           v->Rxbytes, (long) n, GetLocalString( &li, MSG_RETRIES_LEFT ));
  494.               v->xpru.xpru_errormsg = (char *) v->Msgbuf;
  495.               ++v->xpru.xpru_timeouts;
  496.               (*v->io.xpr_update) (&v->xpru);
  497. #ifdef DEBUGLOG
  498.               dlog (v, v->Msgbuf);
  499.               dlog (v, "\n");
  500.               D (DEBUGINFO);
  501. #endif
  502.               continue;
  503.             case GOTCRCW:        /* Sender says it's waiting for an ACK */
  504.               n = v->ErrorLimit;
  505.               if (putsec (v) == ERROR)
  506.                 return ERROR;
  507.               stohdr (v, v->Rxbytes);
  508.               zshhdr (v, ZACK);
  509.               sendbuf (v);
  510.               goto nxthdr;
  511.             case GOTCRCQ:        /* Sender says it's not waiting, */
  512.               /* but ACK anyway (rarely used) */
  513.               n = v->ErrorLimit;
  514.               if (putsec (v) == ERROR)
  515.                 return ERROR;
  516.               stohdr (v, v->Rxbytes);
  517.               zshhdr (v, ZACK);
  518.               sendbuf (v);
  519.               goto moredata;
  520.             case GOTCRCG:        /* Sender says keep receiving, there's more coming */
  521.               n = v->ErrorLimit;
  522.               if (putsec (v) == ERROR)
  523.                 return ERROR;
  524.               goto moredata;
  525.             case GOTCRCE:        /* Sender says this is the last packet */
  526.               n = v->ErrorLimit;
  527.               if (putsec (v) == ERROR)
  528.                 return ERROR;
  529.               goto nxthdr;
  530.             }
  531.         }
  532.     }
  533. }                                /* End of short rzfile() */
  534.  
  535. /**********************************************************
  536.  *      short procheader(struct Vars *v)
  537.  *
  538.  * Process file name & info packet; either open file and
  539.  * prepare to receive, or return ERROR if we should skip
  540.  * this one for some reason
  541.  **********************************************************/
  542. short
  543. procheader (struct Vars *v)
  544. {
  545.   struct SetupVars *sv;
  546.   UBYTE *p, *openmode, buff[PATHLEN];
  547.   long n;
  548.  
  549. #ifdef DEBUGLOG
  550.   D (DEBUGINFO);
  551. #endif
  552.  
  553.   openmode = "w";
  554.   v->Strtpos = 0;
  555.  
  556.   /* Extract expected filesize from file info packet, if given */
  557.   v->Fsize = -1;
  558.   p = strchr (v->Pktbuf, '\0') + 1;
  559.   if (*p)
  560.     v->Fsize = atol (p);
  561.   /*
  562.      * Make sure we have room for file; skip it if not.
  563.      * Commented out for now, since getfree() isn't implemented yet.
  564.      if (v->Fsize > getfree())
  565.      {
  566.      xprsprintf(v->Msgbuf, GetLocalString( &li, MSG_INSUFFICIENT_DISK_SPACE ),
  567.      v->Fsize, getfree());
  568.      upderr(v, v->Msgbuf, XPRU_DNLOAD);
  569.      v->Noroom = TRUE;
  570.      return ERROR;
  571.      }
  572.    */
  573.  
  574.   /* If option RY set, use full received file path */
  575.   sv = (void *) v->io.xpr_data;
  576.   if (*sv->option_r == 'Y')
  577.     strcpy (v->Filename, v->Pktbuf);
  578.   else
  579.     {
  580.       /* else use the default directory path specified in the setup options */
  581.       strcpy (v->Filename, sv->option_p);
  582.       p = v->Filename + strlen (v->Filename) - 1;
  583.       if (p >= v->Filename && *p != '/' && *p != ':')
  584.         *++p = '/';
  585.       *++p = '\0';
  586.       /*
  587.          * Append the filename from the file info packet; ignore anything before
  588.          * last /, \, or : in filename (received directory path is ignored)
  589.        */
  590.       p = strchr (v->Pktbuf, '\0');        /* start at end and scan back */
  591.       /* to start of name */
  592.       while (p >= v->Pktbuf && *p != '/' && *p != '\\' && *p != ':')
  593.         --p;
  594.       strcat (v->Filename, ++p);
  595.     }
  596.  
  597.   /* Display name of file being received for user */
  598.   v->xpru.xpru_updatemask = XPRU_DNLOAD | XPRU_FILENAME;
  599.   v->xpru.xpru_filename = (char *) v->Filename;
  600.   (*v->io.xpr_update) (&v->xpru);
  601.  
  602.   /*
  603.      * If a file with this name already exists, handle in
  604.      * accordance with O option
  605.    */
  606.   if (exist (v))
  607.     {
  608.       switch (*sv->option_o)
  609.         {
  610.         case 'N':                /* Don't overwrite; change name to prevent collision */
  611.           strcpy (buff, v->Filename);
  612.           strcat (v->Filename, ".dup");
  613.           n = 2;
  614.           while (exist (v))
  615.             {
  616.               xprsprintf (v->Filename, "%s.dup%ld", buff, n);
  617.               ++n;
  618.             }
  619.           /* Update filename display to show new name */
  620.           (*v->io.xpr_update) (&v->xpru);
  621.           break;
  622.         case 'R':                /* Resume transfer from current end of file */
  623.           openmode = "a";
  624.           v->Strtpos = (*v->io.xpr_finfo) (v->Filename, 1L);
  625.           break;
  626.         case 'S':                /* Skip it */
  627.           upderr (v, GetLocalString( &li, MSG_FILE_EXISTS ), XPRU_DNLOAD);
  628.           return ERROR;
  629.           /* Else 'Y', go ahead and overwrite it (openmode = w) */
  630.         }
  631.     }
  632.  
  633.   /* Set text/binary mode according to options before opening file */
  634.   set_textmode (v);
  635.  
  636.   /*
  637.      * Figure out file translation mode to use; either binary (verbatim
  638.      * transfer) or ASCII (perform end-of-line conversions).  If user has
  639.      * specified a mode (TY or TN), that's what we use.  If user says use
  640.      * sender's suggestion (T?), set mode according to Zconv flag.  If neither
  641.      * side specifies, default to binary mode.
  642.    */
  643.   v->Thisbinary = v->Rxbinary || !v->Rxascii;
  644.   if (!v->Rxbinary && v->Zconv == ZCNL)
  645.     v->Thisbinary = FALSE;
  646.   if (!v->Rxascii && v->Zconv == ZCBIN)
  647.     v->Thisbinary = TRUE;
  648.  
  649.   /* Open the file (finally) */
  650.   if (!(v->File = bfopen (v, openmode)))
  651.     {
  652.       ++v->Errcnt;
  653.       upderr (v, GetLocalString( &li, MSG_CANT_OPEN_FILE ), XPRU_DNLOAD);
  654.       return ERROR;
  655.     }
  656.   getsystime (&v->Starttime);
  657.  
  658.   /* Initialize comm program transfer status display */
  659.   if (v->NoMask) 
  660.     v->xpru.xpru_updatemask = XPRU_PROTOCOL | XPRU_FILESIZE | XPRU_MSG
  661.       | XPRU_BLOCKS | XPRU_ERRORS | XPRU_TIMEOUTS | XPRU_BLOCKCHECK
  662.       | XPRU_BYTES | XPRU_EXPECTTIME | XPRU_ELAPSEDTIME | XPRU_DATARATE | XPRU_BLOCKSIZE;
  663.   else
  664.     v->xpru.xpru_updatemask = XPRU_DNLOAD | XPRU_PROTOCOL | XPRU_FILESIZE | XPRU_MSG
  665.       | XPRU_BLOCKS | XPRU_ERRORS | XPRU_TIMEOUTS | XPRU_BLOCKCHECK
  666.       | XPRU_BYTES | XPRU_EXPECTTIME | XPRU_ELAPSEDTIME | XPRU_DATARATE | XPRU_BLOCKSIZE;
  667.  
  668.   if (v->SmallBlocks || (v->Ksize == 1024))
  669.     v->xpru.xpru_protocol = (v->FTNmode) ? "ZedZip" : "Zmodem";
  670.   else 
  671.     v->xpru.xpru_protocol = (v->FTNmode) ? "ZedZap" : "SZmodem";
  672.  
  673.   if (v->dzap)
  674.     v->xpru.xpru_protocol = "DirectZap";
  675.  
  676.   v->xpru.xpru_filesize = v->Fsize;
  677.   v->xpru.xpru_msg = (v->Thisbinary) ? GetLocalString( &li, MSG_RECEIVE_BINARY )
  678.     : GetLocalString( &li, MSG_RECEIVE_TEXT );
  679.   v->xpru.xpru_blocks = v->xpru.xpru_errors = v->xpru.xpru_timeouts = 0;
  680.   v->xpru.xpru_blockcheck = v->Crc32 ? "CRC-32" : "CRC-16";
  681.   v->xpru.xpru_bytes = v->Strtpos;
  682.   v->xpru.xpru_blocksize = v->Ksize;  
  683.   update_rate (v);
  684.   (*v->io.xpr_update) (&v->xpru);
  685.   if (v->Strtpos != 0)
  686.     updmsg (v, GetLocalString( &li, MSG_RESUMING_RECV ), XPRU_DNLOAD);
  687.  
  688. #ifdef DEBUGLOG
  689.   D (DEBUGINFO);
  690. #endif
  691.  
  692.   return OK;
  693. }                                /* End of short procheader() */
  694.  
  695. /**********************************************************
  696.  *      short putsec(struct Vars *v)
  697.  *
  698.  * Writes the received file data to the output file.
  699.  * If in ASCII mode, stops writing at first ^Z, and converts all
  700.  * \r\n pairs or solo \r's to \n's.
  701.  **********************************************************/
  702. short
  703. putsec (struct Vars *v)
  704. {
  705.   static char nl = '\n';
  706.   UBYTE *p;
  707.   short n;
  708.  
  709. #ifdef DEBUGLOG
  710.   D (DEBUGINFO);
  711. #endif
  712.  
  713.   /* If in binary mode, write it out verbatim */
  714.   if (v->Thisbinary)
  715.     {
  716.       if (bfwrite (v, v->Pktbuf, (long) v->Rxcount) != v->Rxcount)
  717.         goto diskfull;
  718.       /* If in text mode, perform end-of-line cleanup */
  719.     }
  720.   else
  721.     {
  722.       if (v->Eofseen)
  723.         return OK;
  724.       for (p = v->Pktbuf, n = v->Rxcount; --n >= 0; ++p)
  725.         {
  726.           if (*p == CPMEOF)
  727.             {
  728.               v->Eofseen = TRUE;
  729.               return OK;
  730.             }
  731.           else if (*p != '\n' && v->Lastsent == '\r')
  732.             {
  733.               if (bfwrite (v, &nl, 1L) != 1)
  734.                 goto diskfull;
  735.             }
  736.           if (*p != '\r' && bfwrite (v, p, 1L) != 1)
  737.             goto diskfull;
  738.           v->Lastsent = *p;
  739.         }
  740.     }
  741.  
  742.   /* Update comm program status display */
  743.   if (v->NoMask) 
  744.     v->xpru.xpru_updatemask = XPRU_BLOCKS | XPRU_BLOCKSIZE | XPRU_BYTES
  745.       | XPRU_EXPECTTIME | XPRU_ELAPSEDTIME | XPRU_DATARATE | XPRU_BLOCKCHECK;
  746.   else 
  747.     v->xpru.xpru_updatemask = XPRU_DNLOAD | XPRU_BLOCKS | XPRU_BLOCKSIZE | XPRU_BYTES
  748.       | XPRU_EXPECTTIME | XPRU_ELAPSEDTIME | XPRU_DATARATE | XPRU_BLOCKCHECK;
  749.   ++v->xpru.xpru_blocks;
  750.   v->xpru.xpru_blocksize = v->Rxcount;
  751.   v->xpru.xpru_bytes = v->Rxbytes += v->Rxcount;
  752.   v->xpru.xpru_blockcheck = v->Crc32 ? "CRC-32" : "CRC-16";
  753.   update_rate (v);
  754.   (*v->io.xpr_update) (&v->xpru);
  755.  
  756.   return OK;
  757.  
  758. diskfull:
  759.   upderr (v, GetLocalString( &li, MSG_ERROR_WRITING_FILE ), XPRU_DNLOAD);
  760.   v->Noroom = TRUE;
  761.   return ERROR;
  762. }                                /* End of short putsec() */
  763.  
  764. /**********************************************************
  765.  *      void ackbibi(struct Vars *v)
  766.  *
  767.  * End of batch transmission; disengage cleanly from sender
  768.  **********************************************************/
  769. void
  770. ackbibi (struct Vars *v)
  771. {
  772.   short n;
  773.  
  774. #ifdef DEBUGLOG
  775.   dlog (v, "ackbibi:\n");
  776.   D (DEBUGINFO);
  777. #endif
  778.   stohdr (v, 0L);
  779.   if (v->FTNmode)
  780.   {
  781.     zshhdr (v, ZFIN);
  782.     sendbuf (v);
  783.     return;
  784.   }
  785.   else 
  786.   {
  787.     for (n = 4; --n;)
  788.       {
  789.         zshhdr (v, ZFIN);
  790.         sendbuf (v);
  791.         switch (readock (v, 100))
  792.           {
  793.           case 'O':
  794.             readock (v, 1);        /* Discard 2nd 'O' */
  795.           case TIMEOUT:
  796.           case RCDO:
  797.             return;
  798.           }
  799.       }
  800.   }
  801. }                                /* End of void ackbibi() */
  802. /* End of Receive.c source */
  803.